package com.drakulo.games.ais.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.newdawn.slick.tiled.TiledMap;

import com.drakulo.games.ais.core.audio.SoundHelper;
import com.drakulo.games.ais.core.building.Building;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.delayed.ResearchAction;
import com.drakulo.games.ais.core.delayed.ColonyAction;
import com.drakulo.games.ais.ui.state.SectorState;

/**
 * A colony is established in a sector of a planet. EAch colony manage it's own
 * resources and actions.
 * 
 * @author Drakulo
 * 
 */
public class Colony {
	/** The colony name */
	private String name;
	/** This map contains all resources */
	private Map<Resource, BigDecimal> resources;
	/** The current resources modifiers */
	private transient Map<Resource, BigDecimal> lastModifiers;
	/** This list contains buildings */
	private List<Building> buildings;
	/** The current research in progress */
	private ResearchAction research;
	/** The list of building constructions and upgrades */
	private List<BuildingAction> buildingActions;
	/** The list of robot actions in progress */
	private List<PreparationAction> preparationAction;
	/** The list of special actions */
	private List<ColonyAction> specialActions;
	/** The total amount of robots owned by the colony */
	private int totalRobots;
	/** The amount of robots not assigned and available for an action */
	private int availableRobots;
	/** The current map displayed */
	private TiledMap map;
	/** This flag indicates if the command center is built */
	private boolean commandCenterBuilt;
	/** This flag indicates if the research center is built */
	private boolean researchCenterBuilt;
	/** Viewport X position */
	private int viewportX;
	/** Viewport Y position */
	private int viewportY;

	/** */
	private boolean commandCenterUnderConstruction;

	public Colony() {
		resources = new HashMap<Resource, BigDecimal>();
		lastModifiers = new HashMap<Resource, BigDecimal>();
		Resource[] res = Resource.values();
		for (Resource r : res) {
			resources.put(r, NumberHelper.scale(BigDecimal.valueOf(0)));
			lastModifiers.put(r, NumberHelper.scale(BigDecimal.valueOf(0)));
		}

		buildings = new ArrayList<Building>();
		research = null;
		buildingActions = new ArrayList<BuildingAction>();
		preparationAction = new ArrayList<PreparationAction>();
		specialActions = new ArrayList<ColonyAction>();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Map<Resource, BigDecimal> getResources() {
		return resources;
	}

	public void setResources(Map<Resource, BigDecimal> resources) {
		this.resources = resources;
	}

	public Map<Resource, BigDecimal> getLastModifiers() {
		return lastModifiers;
	}

	public void setLastModifiers(Map<Resource, BigDecimal> lastModifiers) {
		this.lastModifiers = lastModifiers;
	}

	public List<Building> getBuildings() {
		return buildings;
	}

	public void setBuildings(List<Building> buildings) {
		this.buildings = buildings;
	}

	public ResearchAction getResearch() {
		return research;
	}

	public void setResearch(ResearchAction research) {
		this.research = research;
	}

	public List<BuildingAction> getBuildingActions() {
		return buildingActions;
	}

	public void setBuildingActions(List<BuildingAction> buildingActions) {
		this.buildingActions = buildingActions;
	}

	public List<PreparationAction> getPreparationAction() {
		return preparationAction;
	}

	public void setPreparationAction(List<PreparationAction> preparationAction) {
		this.preparationAction = preparationAction;
	}

	public List<ColonyAction> getSpecialActions() {
		return specialActions;
	}

	public void setSpecialActions(List<ColonyAction> specialActions) {
		this.specialActions = specialActions;
	}

	public int getTotalRobots() {
		return totalRobots;
	}

	public void setTotalRobots(int totalRobots) {
		this.totalRobots = totalRobots;
	}

	public void addRobot() {
		this.totalRobots++;
		this.availableRobots++;
	}

	public int getAvailableRobots() {
		return availableRobots;
	}

	public void setAvailableRobots(int availableRobots) {
		this.availableRobots = availableRobots;
	}

	public TiledMap getMap() {
		return map;
	}

	public void setMap(TiledMap map) {
		this.map = map;
	}

	public boolean isCommandCenterBuilt() {
		return commandCenterBuilt;
	}

	public void setCommandCenterBuilt(boolean commandCenterBuilt) {
		this.commandCenterBuilt = commandCenterBuilt;
		if(commandCenterBuilt){
			commandCenterUnderConstruction = false;
		}
	}

	public boolean isResearchCenterBuilt() {
		return researchCenterBuilt;
	}

	public void setResearchCenterBuilt(boolean researchCenterBuilt) {
		this.researchCenterBuilt = researchCenterBuilt;
	}

	/**
	 * Update a resource with the given delta
	 * 
	 * @param r
	 *            the resource to update
	 * @param delta
	 *            the delta to apply
	 */
	public void updateResource(Resource r, BigDecimal delta) {
		BigDecimal prevValue = this.resources.get(r);
		setResource(r, prevValue.add(delta));
	}

	/**
	 * Puts a resource amount in the store
	 * 
	 * @param r
	 *            the resource type
	 * @param d
	 *            the amount
	 */
	public void setResource(Resource r, BigDecimal d) {
		this.resources.put(r, d);
	}

	public BigDecimal getResource(Resource r) {
		return this.resources.get(r);
	}

	public void requireRobots(int quantity) {
		availableRobots -= quantity;
	}

	public void releaseRobots(int quantity) {
		availableRobots += quantity;
	}

	public void addBuilding(Building b) {
		buildings.add(b);
	}

	public void addPreparationAction(PreparationAction action) {
		preparationAction.add(action);
		requireRobots(action.getRobotsUsed());
	}

	public List<PreparationAction> getPreparationActions() {
		return preparationAction;
	}

	public void setCurrentModifier(Resource r, BigDecimal mod) {
		lastModifiers.put(r, mod);
	}

	public BigDecimal getStorSpace(Resource r) {
		BigDecimal total = BigDecimal.ZERO;
		List<Building> buildings = getBuildings();
		for (Building b : buildings) {
			total = total.add(b.getStoreSpaceFor(r));
		}
		return total;
	}

	/**
	 * Retrun true if a building is at the given position
	 * 
	 * @param x
	 *            X coordinate
	 * @param y
	 *            Y coordinate
	 * @return true or false
	 */
	public boolean positionIsFree(int x, int y) {
		// Buildings
		for (Building b : buildings) {
			if (b.getX() == x && b.getY() == y) {
				return false;
			}
		}

		// Buildings under construction
		for (BuildingAction action : buildingActions) {
			Building b = action.getBuilding();
			if (b.getX() == x && b.getY() == y) {
				return false;
			}
		}

		return true;
	}

	public Building getBuildingAt(int x, int y) {
		for (Building b : buildings) {
			if (b.getX() == x && b.getY() == y) {
				return b;
			}
		}
		// No building was found. May be there is a building under construction?
		for (BuildingAction action : buildingActions) {
			Building b = action.getBuilding();
			if (b != null && b.getX() == x && b.getY() == y) {
				return b;
			}
		}

		return null;
	}

	public void addBuildingAction(BuildingAction action) {
		SoundHelper.playSound(SoundHelper.BUILDING_START);
		buildingActions.add(action);
		requireRobots(action.getRobotsUsed());
	}

	public void addSpecialAction(ColonyAction sa) {
		specialActions.add(sa);
	}

	public String getPlanetName() {
		// TODO Handle Planet management
		return "Mar Sara";
	}

	public int getViewportX() {
		return viewportX;
	}

	public int getViewportY() {
		return viewportY;
	}

	/**
	 * Securely sets the viewport X
	 * 
	 * @param x
	 *            The X coordinate
	 */
	public void setViewportX(int x) {
		final int mapWidth = GameData.getCurrentMapWidth();
		if (x > 0) {
			this.viewportX = 0;
		} else if (x < SectorState.VIEWPORT_WIDTH - mapWidth) {
			this.viewportX = SectorState.VIEWPORT_WIDTH - mapWidth;
		} else {
			this.viewportX = x;
		}
	}

	/**
	 * Securely sets the viewport Y
	 * 
	 * @param y
	 *            The Y coordinate
	 */
	public void setViewportY(int y) {
		final int mapHeight = GameData.getCurrentMapHeight();
		if (y > SectorState.TOP_BAR_HEIGHT) {
			this.viewportY = SectorState.TOP_BAR_HEIGHT;
		} else if (y < SectorState.VIEWPORT_HEIGHT + SectorState.TOP_BAR_HEIGHT
				- mapHeight) {
			this.viewportY = SectorState.VIEWPORT_HEIGHT - mapHeight
					+ SectorState.TOP_BAR_HEIGHT;
		} else {
			this.viewportY = y;
		}
	}
	
	public String toString(){
		return name;
	}
	
	public void setCommandCenterUnderConstruction(boolean val){
		commandCenterUnderConstruction = val;
	}
	public boolean isCommandCenterUnderConstruction() {
		return commandCenterUnderConstruction;
	}
}
